package cn.com.nes.common.util.iot;

import cn.com.nes.mybatis.agent.ope.entity.IsProtocolQueryCommand;
import cn.com.nes.site.entity.em.DataType;
import cn.com.nes.site.entity.em.RegisterTypeEnum;
import cn.com.nes.site.entity.iot.NesProtocolDataSet;
import cn.com.nes.site.entity.iot.RegisterDataItem;
import cn.com.nes.site.module.service.iot.ProtocolService;
import cn.hutool.core.util.ObjUtil;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

public class QueryCommandBuffer {

    private final String protocolId;

    private final String username;

    private final ProtocolService protocolService;

    private final List<IsProtocolQueryCommand> queryCommandList = new ArrayList<>();

    private Deque<NesProtocolDataSet> buffer = new LinkedList<>();

    // 单条指令最多读取的寄存器数（1bit）
    int MAX_READ_REGISTER_COUNT_1_BIT = 80;

    // 单条指令最多读取的寄存器数（16bit）
    int MAX_READ_REGISTER_COUNT_16_BIT = 8;

    // buffer截止地址
    int bufferEndAddress = 0;

    private int count = 0;

    final String slaveAddress;

    public QueryCommandBuffer(String protocolId, String username, String slaveAddress, ProtocolService protocolService,
                              int maxReadRegisterCount1Bit, int maxReadRegisterCount16Bit) {
        this.protocolId = protocolId;
        this.username = username;
        this.protocolService = protocolService;
        this.slaveAddress = slaveAddress;
        this.MAX_READ_REGISTER_COUNT_1_BIT = maxReadRegisterCount1Bit;
        this.MAX_READ_REGISTER_COUNT_16_BIT = maxReadRegisterCount16Bit;
    }

    public void append(NesProtocolDataSet input) {
        if (buffer == null || buffer.isEmpty()) {
            buffer = new LinkedList<>();
        }

        RegisterDataItem current = input.getRegisterDataItem();
        RegisterTypeEnum currentRegisterType = RegisterTypeEnum.valueOf(current.getRegisterType());
        int currentRegisterAddress = current.getRegisterAddress();
        // 将要增加的寄存器数
        int registerCount = getDataItemRegisterCount(current.getDataType());
        if (!buffer.isEmpty()) {
            final RegisterDataItem last = buffer.getLast().getRegisterDataItem();
            RegisterTypeEnum lastRegisterType = RegisterTypeEnum.valueOf(last.getRegisterType());
            // 读取的寄存器类型不一致
            boolean isRegisterTypeNotSame = !currentRegisterType.equals(lastRegisterType);
            // 读取的寄存器地址超出缓冲区范围
            boolean isOutOfBuffer = currentRegisterAddress + registerCount - 1 > bufferEndAddress;
            // 判断是否从缓冲区中生成查询指令
            if (isRegisterTypeNotSame || isOutOfBuffer) {
                flush();
            }
        }

        // add by zhouy
        // --------------------------------------------------------------------
        boolean isReadable = current.getReadable(); // 已经添加到缓存中的字段如果是不可读的
        if(!isReadable){
            flush(); // 生成查询指令
        }else {
            // 判断是否从缓冲区中生成查询指令
            buffer.add(input);
            if (bufferEndAddress == 0) {
                final int maxRegisterCount =
                        currentRegisterType.getBitLength() == 16
                                ? MAX_READ_REGISTER_COUNT_16_BIT
                                : MAX_READ_REGISTER_COUNT_1_BIT;
                bufferEndAddress = currentRegisterAddress - 1 + maxRegisterCount;
            }
            // add by zhouy
            if (ObjUtil.isNotEmpty(current.getCommandCut()) && current.getCommandCut().intValue() == 1) {
                flush();
            }
            count++;
        }
    }

    public void flush() {
        if (buffer == null || buffer.isEmpty()) {
            return;
        }

        final RegisterTypeEnum registerType = RegisterTypeEnum.valueOf(buffer.getFirst().getRegisterDataItem().getRegisterType());
        int lastDataItemEndAddress = buffer.getLast().getRegisterDataItem().getRegisterAddress() +
                getDataItemRegisterCount(buffer.getLast().getRegisterDataItem().getDataType()) - 1;
        int serialRegisterCount = lastDataItemEndAddress - buffer.getFirst().getRegisterDataItem().getRegisterAddress() + 1;
        // 生成指令
        final IsProtocolQueryCommand queryCommand =
                protocolService.generateQueryCommand(buffer.getFirst().getRegisterDataItem().getRegisterAddress(),
                        buffer.getLast().getRegisterDataItem().getRegisterAddress(), serialRegisterCount,
                        registerType, protocolId, username, slaveAddress);

        final int startAddress = buffer.getFirst().getRegisterDataItem().getRegisterAddress();
        for (NesProtocolDataSet dataSet : buffer) {
            dataSet.setQueryCommand(queryCommand);
            dataSet.getDataItemInfo().setQueryCommandId(queryCommand.getQueryCommandId());
            // 返回数据的起始bit位
            int offset = (dataSet.getRegisterDataItem().getRegisterAddress() - startAddress)
                    * registerType.getBitLength();
            // 16bit寄存器截取bit位
            if (dataSet.getRegisterDataItem().getBitAddress() != null && registerType.getBitLength() > 1) {
                // modify by zhouy
                if(! dataSet.getRegisterDataItem().getBitAddress().contains("-")) {
                    // bit位顺序 8-15 0-7
                    int bitAddress = Integer.parseInt(dataSet.getRegisterDataItem().getBitAddress());
                    offset += (bitAddress + 8) % 16;
                }
//                offset += (7 - (bitAddress % 8)) + (bitAddress / 8 * 8);
            }
            dataSet.getDataItemInfo().setStartByte(offset);
        }

        // 重置buffer
        buffer.clear();
        bufferEndAddress = 0;
    }

    // 传参 寄存器类型，当前寄存器地址，前一个寄存器地址
    private int getDataItemRegisterCount(String dataType) {
        DataType dataTypeEnum = DataType.valueOf(dataType);
        // 读取的寄存器数
        return dataTypeEnum.getLength() < 16
                ? 1
                : dataTypeEnum.getLength() % 16 == 0
                ? dataTypeEnum.getLength() / 16
                : dataTypeEnum.getLength() / 16 + 1;
    }

}
